//! @Author: DengLibin
//! @Date: Create in 2024-06-17 16:54:02
//! @Description: 在 Rust 中提取 Microsoft Office 文档（如 DOCX、XLSX、PPTX）的文本内容可以使用 zip 和 quick-xml 库。
//! 因为这些文件格式本质上是 ZIP 文件，并且其内容以 XML 格式存储
//!

use quick_xml::events::Event;
use quick_xml::Reader;
use std::fs::{self, File};
use std::io::{BufReader, Cursor, Read, Write};
use std::path::Path;
use zip::ZipArchive;

/// @Author: DengLibin
/// @Date: Create in 2024-06-17 17:34:13
/// @Description: 读取docx文本
pub fn extract_text_from_docx(path: &str) -> Result<String, Box<dyn std::error::Error>> {
    let file = File::open(path)?;

    let mut archive: ZipArchive<BufReader<File>> = ZipArchive::new(BufReader::new(file))?;
    //只读 word/document.xml这个文件
    let mut doc_file = archive.by_name("word/document.xml")?;
    let mut doc_content = Vec::new();
    doc_file.read_to_end(&mut doc_content)?;

    let mut reader = Reader::from_reader(Cursor::new(doc_content));

    let mut buf = Vec::new();
    let mut text_content = String::new();

    // let mut unsupported = false;
    loop {
        if !reader.decoder().encoding().is_ascii_compatible() {
            // unsupported = true;
            break;
        }
        buf.clear();
        match reader.read_event_into(&mut buf)? {
            Event::Eof => break,
            Event::Text(e) => {
                let text = e.unescape()?;
                text_content.push_str(&text);
            }
            Event::Start(ref e) => {
                if e.name().0 == b"w:p" {
                    text_content.push('\n');
                }
            }
            _ => {}
        }
    }

    Ok(text_content)
}

/// @Author: DengLibin
/// @Date: Create in 2024-06-17 17:35:30
/// @Description: 读取xlsx文本
pub fn extract_text_from_xlsx(path: &str) -> Result<String, Box<dyn std::error::Error>> {
    let file = File::open(path)?;
    let mut archive = ZipArchive::new(BufReader::new(file))?;

    let mut text_content = String::new();

    //遍历压缩包中所有文件
    for i in 0..archive.len() {
        let mut file = archive.by_index(i)?;
        if (file.name().starts_with("xl/worksheets/sheet")
            || file.name().starts_with("xl/sharedStrings"))
            && file.name().ends_with(".xml")
        {
            let mut sheet_content = Vec::new();
            file.read_to_end(&mut sheet_content)?;

            let mut reader = Reader::from_reader(Cursor::new(sheet_content));

            let mut buf = Vec::new();

            loop {
                if !reader.decoder().encoding().is_ascii_compatible() {
                    // unsupported = true;
                    break;
                }
                buf.clear();
                match reader.read_event_into(&mut buf)? {
                    Event::Eof => break,
                    Event::Text(e) => {
                        let text = e.unescape()?;
                        text_content.push_str(&text);
                        text_content.push('\t');
                    }
                    Event::End(ref e) => {
                        if e.name().0 == b"row" {
                            text_content.push('\n');
                        }
                    }
                    _ => {}
                }
            }
        }
    }

    Ok(text_content)
}

/// @Author: DengLibin
/// @Date: Create in 2024-06-17 17:56:07
/// @Description: 读取pptx文本

pub fn extract_text_from_pptx(path: &str) -> Result<String, Box<dyn std::error::Error>> {
    let file = File::open(path)?;
    let mut archive = ZipArchive::new(BufReader::new(file))?;
    let mut text_content = String::new();
    let mut index: u32 = 0;

    for i in 0..archive.len() {
        let file = archive.by_index(i)?;
        //没有顺序
        if file.name().starts_with("ppt/slides/slide") && file.name().ends_with(".xml") {
            index += 1;
        }
    }
    for i in 0..index {
        let mut slide_content = Vec::new();
        let mut file = archive.by_name(&format!("ppt/slides/slide{}.xml", (i + 1)))?;
        file.read_to_end(&mut slide_content)?;

        let mut reader = Reader::from_reader(Cursor::new(slide_content));

        let mut buf = Vec::new();
        // text_content.push_str(format!("\n--------------------------------{}----------------------------------\n", file.name()).as_str());ss
        loop {
            if !reader.decoder().encoding().is_ascii_compatible() {
                // unsupported = true;
                break;
            }
            buf.clear();
            match reader.read_event_into(&mut buf)? {
                Event::Eof => break,
                Event::Text(e) => {
                    let text = e.unescape()?;
                    text_content.push_str(&text);
                    text_content.push_str(" ");
                }

                _ => {}
            }
        }
    }

    Ok(text_content)
}

/// @Author: DengLibin
/// @Date: Create in 2024-07-31 17:36:53
/// @Description: 提取office2007文档中的图片
pub fn extract_pic(officex_path: &str, pic_dir: &str) -> Result<(), Box<dyn std::error::Error>> {
    let target_path = Path::new(pic_dir);
    let b = target_path.exists();
    if !b {
        fs::create_dir_all(pic_dir)?;
    }
    // Open the  file
    let file = File::open(officex_path)?;
    let mut archive = zip::ZipArchive::new(file)?;

    // Iterate through the files in the  archive
    for i in 0..archive.len() {
        let mut zip_file = archive.by_index(i)?;
        let file_name = zip_file.name().to_string();

        // println!("文件:{}", file_name);
        // Check if the file is an image (you can add more image formats as needed)
        if file_name.ends_with(".jpeg")
            || file_name.ends_with(".jpg")
            || file_name.ends_with(".png")
        {
            // Prepare the output path for the image file
            let names = file_name.split("/").collect::<Vec<&str>>();
            let last = *names.last().unwrap();
            let output_path = format!("{}/{}", pic_dir, last);

            // Create the output file and write the image data to it
            let mut output_file = File::create(&output_path)?;
            let mut buffer = Vec::new();
            zip_file.read_to_end(&mut buffer)?;
            output_file.write_all(&buffer)?;
        }
    }

    Ok(())
}

/// @Author: DengLibin
/// @Date: Create in 2024-08-14 17:26:39
/// @Description: 提取附件和对象文件
pub fn extract_sub_files(
    officex_path: &str,
    pic_dir: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    let target_path = Path::new(pic_dir);
    let b = target_path.exists();
    if !b {
        fs::create_dir_all(pic_dir)?;
    }
    // Open the  file
    let file = File::open(officex_path)?;
    let mut archive = zip::ZipArchive::new(file)?;
    // Iterate through the files in the  archive
    for i in 0..archive.len() {
        let mut zip_file = archive.by_index(i)?;
        let file_name = zip_file.name().to_string();

        println!("{}", file_name);

        // 如果文件名包含"embeddings"，则可能是嵌入的对象
        if file_name.contains("embeddings/") && !file_name.ends_with("/") {
            let mut embedded_object = Vec::new();
            zip_file.read_to_end(&mut embedded_object)?;

            // 保存嵌入的对象到本地文件 .bin文件，实际是个zip包，解压后的package就是实际的嵌入的对象或附件
            //估计要通过word/media/下的emf图片来获取嵌入的对象
            let file_name = file_name.split("/").last().unwrap();
            let out_path =format!("{}/{}", pic_dir, file_name);
            let out_path = Path::new(out_path.as_str());
            let mut output_file = File::create(out_path)?;
            output_file.write_all(&embedded_object)?;
        }
    }
    Ok(())
}
